package ssau.knyazev.fft.modules.threads;

import java.util.concurrent.CyclicBarrier;

import ssau.knyazev.core.CComplex;

public class CComplexThread implements Runnable{

	protected int idx;
	protected int idy;
	protected int uid;
	protected int blockX;
	protected int blockY;
	private CComplex[][] data = null;
	private CyclicBarrier barrier = null;
	private CComplex[] wilist = null;
	private CComplex[] wjlist = null;
	
	
	public CComplexThread(CyclicBarrier barrier, int idx, int idy, int blockX, int blockY, CComplex[][] data, CComplex[] wilist, CComplex[] wjlist){
		this.idx = idx;
		this.idy = idy;
		this.uid = idy*blockX + idx;
		this.data = data;
		this.blockX = blockX;
		this.blockY = blockY;
		this.wilist = wilist;
		this.wjlist = wjlist;
		this.barrier = barrier;
	}
	
	public void run() {
		int N = data.length;
		int size = 0;
		for (int x = data.length; x > 1; x = x >> 1){
			size++;
		}
		int step, step2;
		int borderDown = ((idx+1)*N/blockX);
		int borderRight = ((idy+1)*N/blockY);
		boolean flag;
		for (int q = 0; q < size-1; q++) {
			step = (int)Math.pow(2, q);
			step2 = step*2;
			for (int down = idx*N/blockX; down < borderDown - step; down++) {
				for (int right = idy*N/blockY; right < borderRight - step; right++) {
					flag = (down/step) % 2 + (right/step) % 2 > 0 ? false : true;
					if (flag){
						CComplex t1 = wilist[(down % step2)*(N/step2)];
						CComplex t2 = wjlist[(right % step2)*(N/step2)];
						butterfly(data[down][right], data[down][right + step], data[down + step][right], data[down + step][right + step], t1, t2);
					}
				}
			}
		}
		try {
			barrier.await();
		} catch (Exception e1) {
			e1.printStackTrace();
		}
		if (idx == 0 && idy == 0){
			step = (int)Math.pow(2, size-1);
			step2 = step*2;
			for (int down = 0; down < N - step; down++) {
				for (int right = 0; right < N - step; right++) {
					flag = (down/step) % 2 + (right/step) % 2 > 0 ? false : true;
					if (flag){
						CComplex w1 = wilist[(down % step2)*(N/step2)];
						CComplex w2 = wjlist[(right % step2)*(N/step2)];
						butterfly(data[down][right], data[down][right + step], data[down + step][right], data[down + step][right + step], w1, w2);
					}
				}
			}
		}
		
		
	}
	
	protected static void butterfly(CComplex a00, CComplex a01, CComplex a10, CComplex a11, CComplex wi, CComplex wj) {
		CComplex newa00 = a00.clone();
		CComplex newa10 = a00.clone();
		CComplex newa01 = a00.clone();
		CComplex newa11 = a00.clone();
		
		CComplex t = wi.multy(a10);
		newa00 = newa00.add(t);
		newa10 = newa10.sub(t);
		newa01 = newa01.add(t);
		newa11 = newa11.sub(t);
		
		t = wj.multy(a01);
		newa00 = newa00.add(t);
		newa10 = newa10.add(t);
		newa01 = newa01.sub(t);
		newa11 = newa11.sub(t);
		
		t = wj.multy(a11);
		t = wi.multy(t);
		newa00 = newa00.add(t);
		newa10 = newa10.sub(t);
		newa01 = newa01.sub(t);
		newa11 = newa11.add(t);

		copyValues(a00, newa00);
		copyValues(a01, newa01);
		copyValues(a10, newa10);
		copyValues(a11, newa11);
	}

	protected static void copyValues(CComplex a, CComplex b) {
		a.setA(b.getA());
		a.setB(b.getB());
		a.setC(b.getC());
		a.setD(b.getD());
	}
}
